package cn.leedsoft.luma.test.inner_class;

import cn.leedsoft.luma.test.dynamic_proxy.IUserService;

/**
 * Created by Administrator on 2017/5/26.
 */
public class EnclosingCls {

    private String name = "I'm EnclosingCls";

    public static void main(String[] args) {
        InnerCls innerCls = new EnclosingCls().new InnerCls();//内部类构造方法调用，类似于外部类实例方法的调用。
        innerCls.m();
    }
    class InnerCls {

        public void m() {
            System.out.println(name);//能访问外部类的所有成员
            System.out.println(this);
            System.out.println(EnclosingCls.this);//在内部类中引用外围类对象.this
            System.out.println(new NotPublicNorInnerCls());
            //在同一个java文件中，跟public class同级的类，不是内部类。仅仅是一个default 访问权限的普通类。

            ////局部内部类。。
//            System.out.println(new MethodInside());
            // 不像js的声明前置。如果在局部内部类之前使用，则编译错
            //而普通内部类，则类似外部类的成员变量。不存在顺序问题。
            /*private */ class MethodInside {//局部内部类，不能有访问限定符，因为他不是外部类的成员（一部分）。
                public void m2() {
                    System.out.println("这是一个方法内部类");
                }
            }
            System.out.println(new MethodInside());


            ////匿名内部类
            System.out.println(new IUserService() {
                @Override
                public String sayHello(String str) {
                    return null;
                }
            });
            System.out.println((IUserService) str -> null);//lambda表达式替换条件：接口、只有一个方法
            System.out.println(new UserServiceImpl() {
                @Override//此处，相当于生成了一个继承UserServiceImpl的匿名内部类。不仅仅用于接口
                public String sayHello(String str) {
                    return null;
                }
            });

            ////嵌套类，其实就是普通的类，只是相当于多了一层命名空间。有个区别就是，能访问外部类所有成员
            new Leeds().me();


            ////使用内部类来实现闭包：
            new EnclosingCls().innerClosure().bM();


            ////使用内部类来实现回调------对于事件驱动系统中，为组件注册事件监听器，都是这种用法。
            new EnclosingCls().innerCallback(new B() {
                @Override
                public void bM() {
                    System.out.println("成功处理该事件");
                }
            });
        }
    }

    public void innerCallback(B b) {
        //...某事件发生，调用回调函数
        b.bM();
        //....
    }

    public B innerClosure() {
        final int i = 10;//传入闭包的局部变量，必须是final的
        B b = new B() {
            @Override
            public void bM() {
                System.out.println(i);
                System.out.println("inner class to impl Closure");
            }
        };
//        i = 11;//报错
        return b;
    }


    static class Leeds {
        public void me() {
            System.out.println("这是个嵌套类");
            System.out.println(new EnclosingCls().name);
        }
    }

    private class UserServiceImpl implements IUserService {//私有内部类，可以封装细节。。。无太多实际意义。
        @Override
        public String sayHello(String str) {
            return null;
        }
    }

    ////内部接口，一定是static的。所以叫做嵌套接口
    interface B {
        public void bM();
    }

    private class BImpl implements B {

        @Override
        public void bM() {
            System.out.println("bM");
        }
    }

    public B getB() {
        return new BImpl();
    }
    ////继承内部类：当导出类也是同一个外部类中的内部类时。无影响
    class ExtendsInnerClass extends InnerCls {

    }
}

class NotPublicNorInnerCls {

}
////继承内部类：当一个普通类，继承一个内部类时：
class ExtendsInnerClass extends EnclosingCls.InnerCls {
    //因为内部类内部存在一个指向其外部类的引用。
    //所以必须提供一个构造方法，来提供外部类对象。并在第一行，让外部类对象调用super()来实现指向。
    ExtendsInnerClass(EnclosingCls enclosingCls) {
        enclosingCls.super();
    }
}

////继承内部类：下面这种情况，类似于在内部类所在的外部类内部，再定义一个内部类来继承该内部类。
class ExtendsInnerClass2 extends EnclosingCls {
    class ExtendsInnerClass3 extends InnerCls {

    }
}